"""
Grave! Important! Важно!

Proletoj el ĉiuj landoj, unuiĝu!
Workers of the world, unite!
Пролетарии всех стран, соединяйтесь!

https://tkom.pro
"""

from graphene import relay, types, ObjectType, String, Float, Int, List, Boolean, Field
from graphene_django import DjangoObjectType
from siriuso.api.mixins import SiriusoAuthNode, SiriusoObjectId
from graphene_permissions.permissions import AllowAny
from django.db.models import Q, F
from siriuso.api.filters import SiriusoFilterConnectionField, SiriusoUnionConnectionField
from siriuso.api.types import SiriusoLingvo
from ..models import *
from siriuso.utils import get_lang_kodo, lingvo_kodo_normaligo

from komunumoj.api.schema import *
from versioj.api.schema import *


# ================ Миксины ================ #
class MuroMixin:
    """
    Миксин добавляет в узел Стены поле enskriboj
    со списком записей стены
    """

    def resolve_enskriboj(self, info, **kwargs):
        models = (MuroEnskribo, MurojUzantoEnskribo)
        rel_model = None

        for name, rel in self._meta.model._meta.fields_map.items():
            if rel.related_model in models:
                rel_model = rel.related_model
                break

        if rel_model:
            return rel_model.objects.filter(posedanto=self.posedanto, muro_id=self.uuid)

        return list()


class MuroBildoMixin:
    """
    Миксин преобразует относительные пути
    до изображений в абсолютные
    """

    @staticmethod
    def __resolve_bildo(request, bildo, default=None):
        image = getattr(bildo, 'url') if bildo else default
        return request.build_absolute_uri(image) if image else None

    def resolve_bildo(self, info):
        return MuroBildoMixin.__resolve_bildo(info.context, getattr(self, 'bildo'))


class MuroEnskriboProprietoj(ObjectType):
    __enskribo = None
    __qs = None
    __info = None

    def __init__(self, enskribo, info, *args, **kwargs):
        self.__enskribo = enskribo
        self.__info = info
        super().__init__(*args, **kwargs)

    def __queryset(self):
        if self.__qs:
            return self.__qs

        cond = Q()
        if isinstance(self.__enskribo, MuroEnskribo):
            self.__qs = (MuroEnskriboInterese.objects
                         .filter(cond, enskribo_id=self.__enskribo.uuid, forigo=False))
        else:
            self.__qs = (MurojUzantoEnskriboInterese.objects
                         .filter(cond, enskribo_id=self.__enskribo.uuid, forigo=False))

        return self.__qs

    intereso = Int()
    mia_intereso = Boolean()
    tuta_teleportado = Int()

    def resolve_intereso(self, info):
        return self.__queryset().count()

    def resolve_mia_intereso(self, info):
        if info.context.user.is_authenticated:
            if isinstance(self.__enskribo, MurojUzantoEnskribo):
                qr = {'posedanto': info.context.user}
            else:
                qr = {'autoro': info.context.user}

            return bool(self.__queryset().filter(**qr).count())

        return False

    def resolve_tuta_teleportado(self, info):
        rel_name = 'originalo' if isinstance(self.__enskribo, MuroEnskribo) else 'originalo_uzanto'
        query = {
            rel_name: self.__enskribo,
            'forigo': False,
            'arkivo': False,
            'publikigo': True
        }

        return (
                MuroEnskribo.objects.filter(**query).count() +
                MurojUzantoEnskribo.objects.filter(**query).count()
        )


class MuroEnskriboMixin:
    """
    Миксин добавляет:
    1. поле bildo с адресом картинки публикации
    2. resolve_komentoj для поля со списком комментариев к публикации
    3. statistiko со статистикой данного сообщения
    """
    statistiko = Field(MuroEnskriboProprietoj)
    bildo = String()
    teksto = Field(SiriusoLingvo)

    def resolve_statistiko(self, info):
        return MuroEnskriboProprietoj(enskribo=self, info=info)

    def resolve_bildo(self, info):
        models = (MuroEnskriboBildo, MurojUzantoEnskriboBildo)
        bildo_model = None

        for name, model in self._meta.model._meta.fields_map.items():
            if model.related_model in models:
                bildo_model = model.related_model
                break

        if bildo_model:
            try:
                bildo = bildo_model.objects.get(posedanto_id=getattr(self, 'uuid'), forigo=False)
                image = bildo.bildo.url
                return info.context.build_absolute_uri(image)
            except bildo_model.DoesNotExist:
                pass

        return None

    def resolve_komentoj(self, info, **kwargs):
        models = {
            MuroEnskribo: MuroEnskriboKomento,
            MurojUzantoEnskribo: MurojUzantoEnskriboKomento
        }

        komento_model = None

        for enskribo, komento_model in models.items():
            if self._meta.model == enskribo:
                break

        if komento_model:
            return komento_model.objects.filter(posedanto_id=getattr(self, 'uuid'))

        return list()

    def resolve_komunumo(self, info, **kwargs):
        if not issubclass(self._meta.model, MurojUzantoEnskribo):
            return self.muro.posedanto

        return None

    def resolve_versioj(self, info, **kwargs):
        user = info.context.user
        model = (VersioUzantoEnskribo if issubclass(self._meta.model, MurojUzantoEnskribo)
                 else VersioKomunumoEnskribo)

        perm_name = ('versioj.povas_vidi_uzantan_enskribon_version'
                     if issubclass(self._meta.model, MurojUzantoEnskribo)
                     else 'versioj.povas_vidi_komunuman_enskribon_version')
        lingvo = lingvo_kodo_normaligo(get_lang_kodo(info.context))

        if user.is_authenticated:
            if user.has_perm(perm_name, self):
                return model.objects.filter(posedanto=self, lingvo__kodo=lingvo)
            elif issubclass(self._meta.model, MurojUzantoEnskribo):
                if perms.has_user_page_perm(perm_name):
                    return model.objects.filter(
                        posedanto=self, lingvo__kodo=lingvo, posedanto__posedanto=user
                    )
            elif perms.has_komunumo_adm_perms(perm_name) or perms.has_komunumo_mod_perms(perm_name):
                return model.objects.filter(
                    posedanto=self, lingvo__kodo=lingvo,
                    posedanto__posedanto__komunumoj_komunumomembro_posedanto__tipo__kodo__in=[
                        'komunumano-adm', 'administranto', 'komunumano-mod', 'moderiganto'
                    ],
                    posedanto__posedanto__komunumoj_komunumomembro_posedanto__autoro=user,
                    posedanto__posedanto__komunumoj_komunumomembro_posedanto__forigo=False
                )

        return model.objects.none()


# ========================================= #
#############################################
class MuroEnskriboBildoNode(SiriusoAuthNode, MuroBildoMixin, DjangoObjectType):
    permission_classes = (AllowAny,)

    class Meta:
        model = MuroEnskriboBildo
        filter_fields = {
            'uuid': ['exact'],
            'forigo': ['exact'],
            'posedanto': ['exact'],
        }
        interfaces = (relay.Node,)


class MuroEnskriboKomentoNode(SiriusoAuthNode, SiriusoObjectId, SiriusoPermissions, DjangoObjectType):
    permission_classes = (AllowAny,)

    teksto = Field(SiriusoLingvo)

    class Meta:
        model = MuroEnskriboKomento
        filter_fields = {
            'uuid': ['exact'],
            'posedanto': ['exact'],
            'posedanto__uuid': ['exact'],
            'publikigo': ['exact'],
            'arkivo': ['exact'],
            'forigo': ['exact'],
            'krea_dato': ['exact', 'range', 'gt', 'gte', 'lt', 'lte']
        }
        interfaces = (relay.Node,)


class MuroEnskriboNode(SiriusoAuthNode, SiriusoObjectId, MuroEnskriboMixin, SiriusoPermissions, DjangoObjectType):
    permission_classes = (AllowAny,)

    komentoj = SiriusoFilterConnectionField(MuroEnskriboKomentoNode)
    komunumo = Field(KomunumoNode)
    versioj = SiriusoFilterConnectionField(VersioKomunumoEnskriboNode)

    class Meta:
        model = MuroEnskribo
        filter_fields = ['uuid', 'posedanto__uuid', 'posedanto__id', 'forigo', 'publikigo', 'arkivo']
        interfaces = (relay.Node,)


class MuroNode(SiriusoAuthNode, MuroMixin, DjangoObjectType):
    permission_classes = (AllowAny,)

    enskriboj = SiriusoFilterConnectionField(MuroEnskriboNode)

    class Meta:
        model = Muro
        filter_fields = {
            'posedanto__id': ['exact', 'gt', 'gte', 'lt', 'lte', 'range'],
            'uuid': ['exact'],
            'posedanto': ['exact'],
            'forigo': ['exact']
        }
        interfaces = (relay.Node,)


#############################################
# =================================
class MurojUzantoEnskriboBildoNode(SiriusoAuthNode, MuroBildoMixin, DjangoObjectType):
    permission_classes = (AllowAny,)

    class Meta:
        model = MurojUzantoEnskriboBildo
        filter_fields = {
            'uuid': ['exact'],
            'forigo': ['exact'],
            'posedanto': ['exact'],
        }
        interfaces = (relay.Node,)


class MurojUzantoEnskriboKomentoNode(SiriusoAuthNode, SiriusoObjectId, SiriusoPermissions, DjangoObjectType):
    permission_classes = (AllowAny,)

    teksto = Field(SiriusoLingvo)

    class Meta:
        model = MurojUzantoEnskriboKomento
        filter_fields = {
            'uuid': ['exact'],
            'posedanto': ['exact'],
            'posedanto__uuid': ['exact'],
            'publikigo': ['exact'],
            'arkivo': ['exact'],
            'forigo': ['exact'],
            'krea_dato': ['exact', 'range', 'gt', 'gte', 'lt', 'lte']
        }
        interfaces = (relay.Node,)


class MurojUzantoEnskriboNode(SiriusoAuthNode, SiriusoObjectId, MuroEnskriboMixin, SiriusoPermissions,
                              DjangoObjectType):
    permission_classes = (AllowAny,)

    komentoj = SiriusoFilterConnectionField(MurojUzantoEnskriboKomentoNode)

    versioj = SiriusoFilterConnectionField(VersioUzantoEnskriboNode)

    class Meta:
        model = MurojUzantoEnskribo
        filter_fields = ['uuid', 'posedanto_id', 'forigo', 'publikigo', 'arkivo']
        interfaces = (relay.Node,)


class MurojUzantoMuroNode(SiriusoAuthNode, MuroMixin, DjangoObjectType):
    permission_classes = (AllowAny,)

    enskriboj = SiriusoFilterConnectionField(MurojUzantoEnskriboNode)

    class Meta:
        model = MurojUzantoMuro
        filter_fields = {
            'posedanto__id': ['exact', 'gt', 'gte', 'lt', 'lte', 'range'],
            'uuid': ['exact'],
            'posedanto': ['exact'],
            'forigo': ['exact']
        }
        interfaces = (relay.Node,)


# ===========================

class MurojEnskribo(types.Union):
    class Meta:
        types = (MuroEnskriboNode, MurojUzantoEnskriboNode)


class MurojEnskriboKomento(types.Union):
    class Meta:
        types = (MuroEnskriboKomentoNode, MurojUzantoEnskriboKomentoNode)


class MurojEnskriboUnionConnection(relay.Connection):
    class Meta:
        node = MurojEnskribo


class MuroQuery(ObjectType):
    muroj = SiriusoFilterConnectionField(MuroNode)
    muroj_enskriboj = SiriusoFilterConnectionField(MuroEnskriboNode)
    muroj_enskriboj_komentoj = SiriusoFilterConnectionField(MuroEnskriboKomentoNode)

    uzantoj_muroj = SiriusoFilterConnectionField(MurojUzantoMuroNode)
    uzantoj_muroj_enskriboj = SiriusoFilterConnectionField(MurojUzantoEnskriboNode)
    uzantoj_enskriboj_komentoj = SiriusoFilterConnectionField(MurojUzantoEnskriboKomentoNode)

    novajhoj = SiriusoUnionConnectionField(MurojEnskriboUnionConnection)
